﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Linq;
using nl.tno.ict.multitouch.wpfmultitouch.controls;
using TouchLibEvents;
using System.Timers;
using nl.tno.ict.multitouch.wpfmultitouch.events;
using System.Collections;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace nl.tno.ict.multitouch.wpfmultitouch
{
    public class TouchManager : ITouchManager
    {
        /// <summary>
        /// Start position for each finger
        /// </summary>
        public Dictionary<long, FingerObject> _fingerStartPos;

        
        private Dictionary<long,FingerObject> fingerList;

        private MTProcessing processing { get { return MTProcessing.GetInstance(); } }

        private Dictionary<long, FingerObject> _fingerOldPos;

        public Dictionary<long, FingerObject> FingerStartPos
        {
            get { return _fingerStartPos; }
        }

        public List<FingerObject> Fingers { get { return fingerList.Values.OrderBy(k => k.Id).ToList(); } }

        /// <summary>
        /// List of current fingers
        /// </summary>
        public Dictionary<long, FingerObject> FingerList
        {
            get { return fingerList; }
        }
        public FingerObject LastRemovedFinger;

        public FrameworkElement Element;
        public FrameworkElement Parent;        
        private FingerObject SpeedReference;

        private int _zIndexOld;

        // The offsets from the MTCanvas' edges when the drag operation began.
        
        // Keeps track of which horizontal and vertical offset should be modified for the drag element.
        
        private Point _imgOrigin;
        private Point _lastPosition = new Point();
        public Point RelativePosition;
        public RotateTransform rotateTrans = new RotateTransform();
        public TransformGroup transGroup = new TransformGroup();
        public ScaleTransform scaleTrans = new ScaleTransform();
        public TranslateTransform translateTrans = new TranslateTransform();

        //Test resize/scale stuff...
        private Point _originalDistance;
        private Point _currentDistance;
        private Point _oldCurrentDistance;
        public  Point _centerPoint;
        private Point _oldCenterPoint;
        private Point _oldCenter;
        private Point _currentCenter;
        private Point _startCenter = new Point();
        public Double _current_Distance;
        public Double _oldDistance;
        public Double _currentRotation;
        public Double _oldRotation;

        public bool DetectGroups { get; set; }
        public bool DetectTwinClicks { get; set; }

        // Groups
        public List<List<FingerObject>> groups;
        private Double groupDistanceTreshold = 25;
        private TimeSpan groupTimeStampTreshold = TimeSpan.FromMilliseconds(2000);

        private double _tempWidth;
        private double _tempHeight;

        private double _oldAngle = 0.0;
        private double _currentAngle = 0.0;
        private Point lastposition = new Point(0, 0);
        //End resize/scale stuff...

        private AdornerLayer _adornerLayer;
        private SimpleCircleAdorner _simpleCircleAdorner;
        private ImageAdorner _imageAdorner;
        private KeyboardButtonAdorner _keyboardButtonAdorner;

        private Dictionary<DispatcherTimer, long> _timerTable = new Dictionary<DispatcherTimer, long>();

        private int _fingersDoubleClick = 0;
        private int _fingersDoubleClickTime = 0;

        private bool _simulationEnabled = false;

        //For testing purpose only...
        private Ellipse _test;


        public event Events.TouchEventHandler TwinClick;
        public event Events.TouchEventHandler DoubleClick;
        public event Events.TouchEventHandler NewTouch;
        public event Events.TouchEventHandler UpdateTouch;
        public event Events.TouchEventHandler RemoveTouch;
        public event Events.FingerObjectEventHandler NotMoved;

        private double fadingSpeedX;
        private double fadingSpeedY;

        public object Tag;
        public double scale;

        #region Properties


        public Point OldCenter
        {
            get { return _oldCenter; }
        }
        public Point CurrentCenter
        {
            get { return _currentCenter; }
        }
        public Point StartCenter
        {
            get { return _startCenter; }
        }
        /// <summary>
        /// Gets the amount of fingers touching the object
        /// </summary>
        public int FingerCount { get { return this.fingerList.Count; }}

        /// <summary>
        /// Gets or sets the CanBeClicked property
        /// </summary>
        public bool CanBeClicked
        {
            get { return (bool)Element.GetValue(MTProperties.CanBeClickedProperty); }
            set { Element.SetValue(MTProperties.CanBeClickedProperty, value); }
        }
        /// <summary>
        /// Gets or sets the CanBeDragged property
        /// </summary>
        public bool CanBeDragged
        {
            get { return (bool)Element.GetValue(MTProperties.CanBeDraggedProperty); }
            set { Element.SetValue(MTProperties.CanBeDraggedProperty, value); }
        }
        /// <summary>
        /// Gets or sets the CanBeScaled property
        /// </summary>
        public bool CanBeScaled
        {
            get { return (bool)Element.GetValue(MTProperties.CanBeScaledProperty); }
            set { Element.SetValue(MTProperties.CanBeScaledProperty, value); }
        }
        /// <summary>
        /// Gets or sets the CanBeRotated property
        /// </summary>
        public bool CanBeRotated
        {
            get { return (bool)Element.GetValue(MTProperties.CanBeRotatedProperty); }
            set { Element.SetValue(MTProperties.CanBeClickedProperty, value); }
        }
        /// <summary>
        /// Gets or sets the Isscaling property
        /// </summary>
        public bool IsScaling
        {
            get { return (bool)Element.GetValue(MTProperties.IsScalingProperty); }
            set { Element.SetValue(MTProperties.IsScalingProperty, value); }
        }

        /// <summary>
        /// Gets or sets the IsDragging property
        /// </summary>
        public bool IsDragging
        {
            get { return (bool)Element.GetValue(MTProperties.IsDraggingProperty); }
            set { Element.SetValue(MTProperties.IsDraggingProperty, value); }
        }

        /// <summary>
        /// Gets or sets the IsRotating property
        /// </summary>
        public bool IsRotating
        {
            get { return (bool)Element.GetValue(MTProperties.IsRotatingProperty); }
            set { Element.SetValue(MTProperties.IsRotatingProperty, value); }
        }
        /// <summary>
        /// Gets or sets the AdornersEnabled property
        /// </summary>
        public bool AdornersEnabled
        {
            get { return (bool)Element.GetValue(MTProperties.AdornersEnabledProperty); }
            set { Element.SetValue(MTProperties.AdornersEnabledProperty, value); }
        }

        /// <summary>
        /// Gets or sets the AdornersEnabled property
        /// </summary>
        public bool FingerAdornerEnabled
        {
            get { return (bool)Element.GetValue(MTProperties.FingerAdornerEnabledProperty); }
            set { Element.SetValue(MTProperties.FingerAdornerEnabledProperty, value); }
        }
        /// <summary>
        /// Gets or sets the onTop property. The z-index changes when a finger hits an object.
        /// </summary>
        public bool OnTop
        {
            get { return (bool)Element.GetValue(MTProperties.OnTopProperty); }
            set { Element.SetValue(MTProperties.OnTopProperty, value); }
        }

        #endregion


        public TouchManager()
        {
            DetectGroups = false;
            DetectTwinClicks = false;
        }

        public void InitTransforms()
        {
            if (Element.RenderTransform is TransformGroup)
            {
                TransformGroup tg = (TransformGroup)Element.RenderTransform;
                foreach (Transform t in tg.Children)
                {
                    GetTransform(t);
                }
            }
            else if (Element.RenderTransform is Transform)
            {
                GetTransform((Transform)Element.RenderTransform);
            }

            transGroup = new TransformGroup();
            transGroup.Children.Add(rotateTrans);
            transGroup.Children.Add(scaleTrans);
            transGroup.Children.Add(translateTrans);



        }

        private void GetTransform(Transform t)
        {
            if (t is TranslateTransform) translateTrans = t as TranslateTransform;
            if (t is RotateTransform) rotateTrans = t as RotateTransform;
            if (t is ScaleTransform) scaleTrans = t as ScaleTransform;
        }

        public void Init(FrameworkElement element, FrameworkElement parent, bool simulationEnabled)
        {
            
            Element = element;         
            Parent = parent;

            InitTransforms();

            _fingerStartPos = new Dictionary<long, FingerObject>();
            fingerList = new Dictionary<long, FingerObject>();


            _zIndexOld = MTCanvas.GetZIndex(Element);

            this._simulationEnabled = simulationEnabled;

            if (Element != Parent && AdornersEnabled)
            {
                _adornerLayer = AdornerLayer.GetAdornerLayer(this.Element);
                _simpleCircleAdorner = new SimpleCircleAdorner(this.Element);
                _imageAdorner = new ImageAdorner(this.Element);
                if (Element is MTButton)
                    _keyboardButtonAdorner = new KeyboardButtonAdorner(this.Element);
            }

            if (FingerAdornerEnabled)
            {
                if ((_adornerLayer == null))
                    _adornerLayer = AdornerLayer.GetAdornerLayer(this.Element);
            }

            _originalDistance = new Point(0, 0);
            _currentDistance = new Point(0, 0);
            _oldCurrentDistance = new Point(0, 0);
            _oldCenterPoint = new Point(0, 0);

            //Set transformation props!!

            TransformGroup transformGroup = Element.LayoutTransform as TransformGroup;
            if (transformGroup == null)
            {
                transformGroup = Element.RenderTransform as TransformGroup;
            }
            if (transformGroup != null && transformGroup.Children.Count > 0)
            {
                foreach (Transform trans in transformGroup.Children)
                {
                    if (trans is RotateTransform)
                    {
                        _currentAngle = ((RotateTransform)trans).Angle;
                        rotateTrans.Angle = ((RotateTransform)trans).Angle;
                        _oldAngle = _currentAngle;
                    }
                    else if (trans is ScaleTransform)
                    {
                        scaleTrans = (ScaleTransform)trans;
                    }
                }
            }
            _tempWidth = Element.ActualWidth;
            _tempHeight = Element.ActualHeight;

            _test = new Ellipse();
            _test.Height = 10;
            _test.Width = 10;
            _test.Fill = new SolidColorBrush(Colors.Red);
            if (Parent is MTCanvas)
            {
                //((MTCanvas)_parent).Children.Add(_test);
                MTCanvas.SetZIndex(_test, 1000);
            }

            IsRotating = false;
            StartTransformTimer();
        }

        /// <summary>
        /// This touchmanager will be used when the parent is a MTCanvas
        /// In this class the (mouse) events and some rotating/dragging and scaling wille be done
        /// </summary>
        /// <param name="element">The touched element</param>
        /// <param name="parent">The prarent element of the touched element</param>
        public TouchManager(FrameworkElement element, FrameworkElement parent, bool simulationEnabled)//Verandert in FrameworkElement, er kunnen een aantal methoden verdwijnen!
        {
            Init(element, parent, simulationEnabled);       
        }

        private void detectGroups()
        {
            if (DetectGroups)
            {
                groups = new List<List<FingerObject>>();
                _fingerOldPos = new Dictionary<long, FingerObject>();

                int i = 0;
                foreach (KeyValuePair<long, FingerObject> finger_A in fingerList)
                {
                    FingerObject fo_A = (FingerObject)finger_A.Value;
                    FingerObject fo_A_old = null;
                    if (_fingerOldPos.ContainsKey(finger_A.Key))
                    {
                        fo_A_old = (FingerObject)_fingerOldPos[finger_A.Key];
                    }



                    // check if fo_A is already added to a group
                    List<FingerObject> group = new List<FingerObject>(); ;
                    Boolean foExtist = false;
                    foreach (List<FingerObject> lfo in groups)
                    {
                        foreach (FingerObject fo in lfo)
                        {
                            if (fo_A.Id == fo.Id)
                            {
                                group = lfo;
                                foExtist = true;
                                break;
                            }
                        }
                    }
                    // if not make new group and add fo_A
                    if (!foExtist)
                    {
                        group.Add(fo_A);
                        groups.Add(group);
                    }
                    //



                    int j = 0;
                    foreach (KeyValuePair<long, FingerObject> finger_B in fingerList)
                    {
                        if (j > i)
                        {
                            FingerObject fo_B = (FingerObject)finger_B.Value;
                            FingerObject fo_B_old = null;
                            if (_fingerOldPos.ContainsKey(finger_B.Key))
                            {
                                fo_B_old = (FingerObject)_fingerOldPos[finger_B.Key];
                            }

                            TimeSpan ts = fo_A.CreatedTime - fo_B.CreatedTime;
                            bool b = (ts < groupTimeStampTreshold && ts > -groupTimeStampTreshold);

                            Double d = Math.Sqrt(Math.Pow(fo_B.CurrentPosition.X - fo_A.CurrentPosition.X, 2) + Math.Pow(fo_B.CurrentPosition.Y - fo_A.CurrentPosition.Y, 2));
                            Double d_old = 0;
                            if (fo_B_old != null && fo_A_old != null)
                            {
                                d_old = Math.Sqrt(Math.Pow(fo_B_old.CurrentPosition.X - fo_A_old.CurrentPosition.X, 2) + Math.Pow(fo_B_old.CurrentPosition.Y - fo_A_old.CurrentPosition.Y, 2));
                            }
                            if (b && d < groupDistanceTreshold && d_old < groupDistanceTreshold)
                            {
                                group.Add(fo_B);
                            }

                        }
                        j++;
                    }
                    i++;
                }
            }

        }

        /// <summary>
        /// When a new finger touches the object this method will be used to throw some events
        /// and do some other calculations
        /// </summary>
        /// <param name="obj"></param>
        /// 

        public void NewFinger(Touch obj)
        {


            

            // switch to finger transform
            if (MovementState != MovementStates.fingers) MovementState = MovementStates.fingers;

            Element.Focus();
            if (!fingerList.ContainsKey(obj.Finger.Id))
            {
                obj.Finger.CreatedTime = obj.Finger.LastUpdateTime;
                _fingerOldPos = fingerList;
                _fingerStartPos.Add(obj.Finger.Id, obj.Finger);//Add startposition
                fingerList.Add(obj.Finger.Id, obj.Finger);//Add startposition, this will change.
            }

            detectGroups();

            
          
            //KeyEventArgs kea = new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromVisual(Element), 1, Key.None);
            //kea.RoutedEvent = UIElement.KeyDownEvent;
            //((UIElement)Element).RaiseEvent(kea);

            if (Element is Button && ((Button)Element).ClickMode == ClickMode.Press)
            {
                MouseEventArgs mea = new MouseEventArgs(Mouse.PrimaryDevice, 1, Stylus.CurrentStylusDevice);
                mea.RoutedEvent = Button.ClickEvent;
                ((UIElement)Element).RaiseEvent(mea);
            }
            else
            {
                MouseButtonEventArgs mbe = new MouseButtonEventArgs(Mouse.PrimaryDevice, 1, MouseButton.Left);
                mbe.RoutedEvent = UIElement.MouseDownEvent;
                ((UIElement)Element).RaiseEvent(mbe);

            }

            //prepare the timer for the notmoved event...
            if (DetectTwinClicks)
            {
                DispatcherTimer t = new DispatcherTimer();
                _timerTable.Add(t, obj.Finger.Id);
                t.Interval = new TimeSpan(0, 0, 0, 0, (int)getTimeout());
                t.Tick += new EventHandler(DetectNotMoved);
                t.Start();
            }
            //End of not moved 

            if (Element != Parent && OnTop)
                MTCanvas.SetZIndex(Element, 20);

            if (AdornersEnabled)
                this.addAdornerLayers(1);

            if (FingerAdornerEnabled)
                _adornerLayer.Add(new FingerAdorner(this.Element, obj.Finger));

            _imgOrigin = new Point(MTCanvas.GetLeft(Element) + Element.Width / 2, MTCanvas.GetTop(Element) + Element.Height / 2);
            if (this.fingerList.Count == 2)
            {
                _oldDistance = _current_Distance;
            }
            //Set the fingerCount var.
            if (Element is MTObject)
                ((MTObject)Element).FingerCount = fingerList.Count;

            _oldCenterPoint = new Point(0, 0);

           
            if (NewTouch != null) NewTouch(this, new Events.TouchEventArgs(obj));
           
            _oldCenter = _currentCenter;
            
            _currentCenter = calculateCenterPoint();
            if (FingerCount > maxFingerCount) maxFingerCount = FingerCount;

            SpeedReference = obj.Finger;
            
        }

        void DetectNotMoved(object sender, EventArgs e)
        {
            DispatcherTimer key = sender as DispatcherTimer;
            FingerObject currentpos = null;
            FingerObject startpos = null;
            if (_timerTable.ContainsKey(key))
            {
                long ID = _timerTable[key];

                if (fingerList.ContainsKey(ID))
                {

                    currentpos = fingerList[ID];
                    startpos = (FingerObject)_fingerStartPos[ID];

                    if (_fingerStartPos.Count > 0 && fingerList.Count > 0 &&
                        currentpos != null && startpos != null &&
                        Math.Abs(currentpos.CurrentPosition.X - startpos.CurrentPosition.X) < 5 &&
                        Math.Abs(currentpos.CurrentPosition.Y - startpos.CurrentPosition.Y) < 5)
                    {
                        if (Element is MTObject)
                            ((MTObject)Element).NotMoved();

                        if (this.NotMoved != null) NotMoved(this, new Events.FingerObjectEventArgs(currentpos));
                    }
                }
                key.Stop();//Stop timer
                _timerTable.Remove(key);//Remove the timer

            }
        }

        
        public double currentRotation()
        {
            _oldRotation = _currentRotation;
            if (_fingerStartPos.Count > 1)
            {
                int i = _fingerStartPos.Count;
                FingerObject foCurrentA = null;
                FingerObject foCurrentB = null;
                
                foreach (KeyValuePair<long,FingerObject> finger in fingerList)
                {
                    i--;
                    if (i == 0)
                    {
                        foCurrentA = (FingerObject)finger.Value;
                    }
                    else if (i == 1)
                    {
                        foCurrentB = (FingerObject)finger.Value;
                    }
                }
                Double grad = (Double)(180 / (Double)Math.PI);
                //double x = foCurrentA.CurrentPosition.X - foCurrentB.CurrentPosition.X;
                //double y = foCurrentA.CurrentPosition.Y - foCurrentB.CurrentPosition.Y;
                //double d = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2));
                //double a2 = Math.Sinh(y / d) * grad;
                double aCurrent = Math.Atan2((foCurrentA.CurrentPosition.X - foCurrentB.CurrentPosition.X), (foCurrentA.CurrentPosition.Y - foCurrentB.CurrentPosition.Y)) * grad;
                
                double a = aCurrent;
                //if (a < -180) { a = a + 360; }
                _currentRotation = a;
                return (a);
            }
            else
            {
                _currentRotation = 0;
                return 0;
            }
        }
        private Point calculateDistance(string type)
        {
            double x = 0;
            double y = 0;
            if (type == "start")
            {
                foreach (KeyValuePair<long,FingerObject> finger in _fingerStartPos)
                {
                    x += Math.Abs(_centerPoint.X - ((FingerObject)finger.Value).CurrentPosition.X);
                    y += Math.Abs(_centerPoint.Y - ((FingerObject)finger.Value).CurrentPosition.Y);
                }
            }
            else if (type == "current")
            {
                foreach (KeyValuePair<long,FingerObject> finger in fingerList)
                {
                    x += Math.Abs(_centerPoint.X - ((FingerObject)finger.Value).CurrentPosition.X);
                    y += Math.Abs(_centerPoint.Y - ((FingerObject)finger.Value).CurrentPosition.Y);
                }
            }
            return new Point(x/_fingerStartPos.Count, y/_fingerStartPos.Count);
        }

        public Point calculateCenterPoint()
        {
            double x = 0;
            double y = 0;
            
            foreach (KeyValuePair<long,FingerObject> finger in fingerList)
            {
                x += ((FingerObject)finger.Value).CurrentPosition.X;
                y += ((FingerObject)finger.Value).CurrentPosition.Y;
            }
            if (fingerList.Count == 0)
            {
                return new Point(0, 0);
            }
            else
            {
                return new Point(x / fingerList.Count, y / fingerList.Count);
            }
        }
        
        /// <summary>
        /// Method what checks if the finger hasn't moved for the TIMEOUT specified time. Set the Timeout 
        /// property to change the timeout.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void t_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                
            }
            catch (Exception ex) { Console.WriteLine("Error: " + ex.ToString()); }
        }

        /// <summary>
        /// Gets the timeout from an object. 
        /// </summary>
        /// <returns></returns>
        private double getTimeout()
        {
            if (Element is MTObject)
                return ((MTObject)Element).Timeout;
            return 1000.0;
        }

        /// <summary>
        /// When a finger leaves/drags from an object this method will be used
        /// </summary>
        /// <param name="fo"></param>
        public void RemoveFinger(Touch t)
        {
            FingerObject fo = t.Finger;
            if (RemoveTouch != null) RemoveTouch(this, new Events.TouchEventArgs(t));

           
            
            //Remove finger from list
            _fingerStartPos.Remove(fo.Id);
            fingerList.Remove(fo.Id);
            
            if (AdornersEnabled)
                this.removeAdornerLayers(0);

            if (FingerAdornerEnabled)
            {
                foreach (Adorner adorner in _adornerLayer.GetAdorners(this.Element))
                {
                    if (adorner is FingerAdorner)
                        if (((FingerAdorner)adorner).Obj.Id == fo.Id)
                            _adornerLayer.Remove(adorner);
                }
            }

            if (fingerList.Count == 0)
            {



                if(OnTop)
                    MTCanvas.SetZIndex(Element, _zIndexOld);

                MouseEventArgs mea = new MouseEventArgs(Mouse.PrimaryDevice, 1);
                mea.RoutedEvent = UIElement.MouseLeaveEvent;
                //((UIElement)_element).RaiseEvent(mea);

                MouseButtonEventArgs mbe = new MouseButtonEventArgs(Mouse.PrimaryDevice, 1, MouseButton.Left);
                mbe.RoutedEvent = UIElement.MouseUpEvent;
                ((UIElement)Element).RaiseEvent(mbe);

                if (Element is MTButton)
                {
                    //KeyEventArgs kea = new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromVisual(Element), 1, Key.None);
                    //kea.RoutedEvent = UIElement.KeyUpEvent;
                    //((UIElement)Element).RaiseEvent(kea);



                }

                IsDragging = false;
            }
            if (CanBeClicked && (Element is MTRadioButton || Element is MTCheckBox))
            {
                MouseButtonEventArgs mbea = new MouseButtonEventArgs(Mouse.PrimaryDevice, 1, MouseButton.Left);
                mbea.RoutedEvent = Button.ClickEvent;
                Element.RaiseEvent(mbea);
            }

            if (Element is MTObject)
                ((MTObject)Element).FingerCount = fingerList.Count;


            if (fingerList.Count > 1)
            {
                _centerPoint = calculateCenterPoint();
                _currentDistance = calculateDistance("current");
                _oldCurrentDistance = _currentDistance;
            }
            _oldCenterPoint = new Point(0, 0);
            _fingerOldPos = fingerList;
        }

        /// <summary>
        /// When a finger raises this method will be used
        /// </summary>
        /// <param name="fo"></param>
        /// 
        public double calculate2PDistanceStart()
        {
            if (_fingerStartPos.Count > 1)
            {
                int i = _fingerStartPos.Count;
                FingerObject foA = null;
                FingerObject foB = null;
                foreach (KeyValuePair<long,FingerObject> finger in _fingerStartPos)
                {
                    i--;
                    if (i == 0)
                    {
                        foA = (FingerObject)finger.Value;
                    }
                    else if (i == 1)
                    {
                        foB = (FingerObject)finger.Value;
                    }
                }
                double d = Math.Sqrt(Math.Pow((foA.CurrentPosition.X - foB.CurrentPosition.X), 2) + Math.Pow((foA.CurrentPosition.Y - foB.CurrentPosition.Y), 2));


                return d;
            }
            else
            {
                return 0;
            }
        }
        public double calculate2PDistanceCurrent()
        {
            _oldDistance = _current_Distance;
            if (_fingerStartPos.Count > 1)
            {
                int i = _fingerStartPos.Count;
                FingerObject foCurrentA = null;
                FingerObject foCurrentB = null;
                foreach (KeyValuePair<long,FingerObject> finger in fingerList)
                {
                    i--;
                    if (i == 0)
                    {
                        foCurrentA = (FingerObject)finger.Value;
                    }
                    else if (i == 1)
                    {
                        foCurrentB = (FingerObject)finger.Value;
                    }
                }
                double d = Math.Sqrt(Math.Pow((foCurrentA.CurrentPosition.X - foCurrentB.CurrentPosition.X), 2) + Math.Pow((foCurrentA.CurrentPosition.Y - foCurrentB.CurrentPosition.Y), 2));

                _current_Distance = d;
                return d;
            }
            else
            {
                _current_Distance = 0;
                return 0;
            }
        }

        
        
        private void CalculateSpeed()
        {
            if (FingerCount == 1 && MovementState == MovementStates.fingers)
            {
                if (SpeedReference != null)
                {
                    double timediff = (Fingers[0].LastUpdateTime - SpeedReference.LastUpdateTime).TotalMilliseconds;
                    if (timediff > 20)
                    {
                        fadingSpeedX = (Fingers[0].RelativePosition.X - SpeedReference.RelativePosition.X) / timediff;
                        fadingSpeedY = (Fingers[0].RelativePosition.Y - SpeedReference.RelativePosition.Y) / timediff;
                        SpeedReference = Fingers[0];
                    }
                    else
                    {
                        fadingSpeedX = 0;
                        fadingSpeedY = 0;
                    }
                }
            }
            else
            {
                ResetFadeCalculations();
                if (MovementState == MovementStates.fingers) MovementState = MovementStates.none;
            }
            
            
        }

        public void ResetFadeCalculations()
        {
            SpeedReference = null;
            fadingSpeedX = 0;
            fadingSpeedY = 0;
        }

        public void FingerRaised(FingerObject FingerLastPos)
        {
            IsRotating = false;
            
            // get time on table
            FingerObject fo = FingerList[FingerLastPos.Id];
            double TimeOnTable = (DateTime.Now.Subtract(fo.CreatedTime).Ticks / TimeSpan.TicksPerMillisecond);
            //MTProcessing.GetInstance().WriteToDebug(TimeOnTable.ToString());
            //MTProcessing.GetInstance().WriteToDebug(fo.StartTime.ToString());
            
            //Remove finger from list
            LastRemovedFinger = FingerLastPos;

            _fingerStartPos.Remove(FingerLastPos.Id);
            fingerList.Remove(FingerLastPos.Id);
            if (this.fingerList.Count == 1)
            {
                _oldDistance = _current_Distance;
            }

            detectGroups();

            //Raise some event(s)
            if (fingerList.Count == 0)
            {

                
                if (CanBeDragged && maxFingerCount == 1)
                {
                    
                    MovementState = MovementStates.fading;                    
                }
                
                MouseButtonEventArgs mbe = new MouseButtonEventArgs(Mouse.PrimaryDevice, 1, MouseButton.Left);
                //mbe.RoutedEvent = UIElement.PreviewMouseUpEvent; --> Generates error:(
                //((UIElement)_element).RaiseEvent(mbe);

                
                //mbe.RoutedEvent = MTCheckBox.CheckedEvent;
                //_element.RaiseEvent(mbe);

                if (CanBeClicked)
                {

                    if (Element is Button)
                    {

                        if (((Button)Element).ClickMode == ClickMode.Release)
                        {
                            MouseButtonEventArgs mbea = new MouseButtonEventArgs(Mouse.PrimaryDevice, 1, MouseButton.Left);
                            mbea.RoutedEvent = Button.ClickEvent;
                            Element.RaiseEvent(mbea);
                        }
                        PresentationSource ps = PresentationSource.FromVisual(Element);
                        if (ps != null)
                        {
                            KeyEventArgs kea = new KeyEventArgs(Keyboard.PrimaryDevice, ps, 1, Key.None);
                            kea.RoutedEvent = UIElement.KeyUpEvent;
                            UIElement TElement = ((UIElement)Element);
                            TElement.RaiseEvent(kea);
                        }
                    }
                    else
                    {

                        PresentationSource ps = PresentationSource.FromVisual(Element);
                        if (ps != null)
                        {
                            KeyEventArgs kea = new KeyEventArgs(Keyboard.PrimaryDevice, ps, 1, Key.None);
                            kea.RoutedEvent = UIElement.KeyUpEvent;
                            UIElement TElement = ((UIElement)Element);
                            TElement.RaiseEvent(kea);
                        }


                        MouseEventArgs mea = new MouseEventArgs(Mouse.PrimaryDevice, 1, Stylus.CurrentStylusDevice);
                        mea.RoutedEvent = UIElement.MouseLeaveEvent;
                        ((UIElement)Element).RaiseEvent(mea);


                        mbe.RoutedEvent = UIElement.MouseUpEvent;
                        ((UIElement)Element).RaiseEvent(mbe);

                    }
                }

                if (CanBeClicked && !this._simulationEnabled)
                {
                    
                }

                _oldCenter = _currentCenter;
                _currentCenter = calculateCenterPoint();
                maxFingerCount = 0;
            }

            //set some properties
            if (fingerList.Count == 1)
            {
                IsRotating = false;
                IsScaling = false;
            }

            //Set the z index to normal
            if (fingerList.Count == 0 && OnTop)
            {
                MTCanvas.SetZIndex(Element, _zIndexOld);
            }

            // check double click

            
            if (TimeOnTable<200)
            {
                _fingersDoubleClick += 1;
           

            if (_fingersDoubleClick >= 2)
            {
                
                if (Environment.TickCount - _fingersDoubleClickTime <= 500)
                {
                    Touch dt = new Touch(null, FingerLastPos);
                    dt.Finger = FingerLastPos;
                    if (this.DoubleClick != null) this.DoubleClick(this, new Events.TouchEventArgs(dt));
                    MouseButtonEventArgs mbe = new MouseButtonEventArgs(Mouse.PrimaryDevice, 1, MouseButton.Left);
                    mbe.RoutedEvent = MTButton.MouseDoubleClickEvent;
                    ((UIElement)Element).RaiseEvent(mbe);
               

                }
                _fingersDoubleClick = 0;
                _fingersDoubleClickTime = Environment.TickCount;
                _fingersDoubleClick = 1;
            }
            else
            {
                
                _fingersDoubleClickTime = Environment.TickCount;
                _fingersDoubleClick = 1;
            }
            }


            if (AdornersEnabled)
                this.removeAdornerLayers(0);

            if (FingerAdornerEnabled)
            {
                foreach (Adorner adorner in _adornerLayer.GetAdorners(this.Element))
                {
                    if (adorner is FingerAdorner)
                        if (((FingerAdorner)adorner).Obj.Id == FingerLastPos.Id)
                            _adornerLayer.Remove(adorner);
                }
            }

            

            if (Element is MTObject)
                ((MTObject)Element).FingerCount = fingerList.Count;

            if (fingerList.Count > 1)
            {
                _centerPoint = calculateCenterPoint();
                _currentDistance = calculateDistance("current");
                _oldCurrentDistance = _currentDistance;

                // check for twinclick (two at the same time for a short period)



            }

            if (fingerList.Count == 0)
            {
                IsDragging = false;
            }



            _oldCenterPoint = new Point(0, 0);

            Touch t = new Touch(null, FingerLastPos);
            t.Finger = FingerLastPos;
            t.TouchManager = this;
            if (RemoveTouch != null) RemoveTouch(this, new Events.TouchEventArgs(t));

            
        }

        List<TuioMoveFingerEventArgs> history;

        /// <summary>
        /// Set new position of a existing finger and do some scaling, rotating and draggin 
        /// </summary>
        /// <param name="FingerNewPos">The new position of a finger</param>
        public void UpdateFinger(Touch t, List<TuioMoveFingerEventArgs> history)
        {
            
            t.TouchManager = this;
            if (t.Finger != null)
            {
                this.history = history;

                FingerObject FingerNewPos = t.Finger;
                try
                {
                   
                    //Set the heigth and width of a object used by the scale/rotate method's
                    _imgOrigin = new Point(MTCanvas.GetLeft(Element) + Width(Element) / 2, MTCanvas.GetTop(Element) + Height(Element) / 2);

                    //checks if the finger position has changed.. if not, quit this method
                    if (fingerPosChanged(fingerList[FingerNewPos.Id], FingerNewPos))
                    {
                        // get start time from last finger
                        FingerNewPos.CreatedTime = (fingerList[FingerNewPos.Id] as FingerObject).CreatedTime;
                        // set last position from last finger
                        FingerNewPos.LastPosition = (fingerList[FingerNewPos.Id] as FingerObject).CurrentPosition;
                        fingerList[FingerNewPos.Id] = FingerNewPos;

                    }
                    else
                        return;
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error updating finger: " + e.Message);
                }

                if (FingerAdornerEnabled)
                {
                    foreach (Adorner adorner in _adornerLayer.GetAdorners(this.Element))
                    {
                        if (adorner is FingerAdorner)
                            if (((FingerAdorner)adorner).Obj.Id == FingerNewPos.Id)
                                _adornerLayer.Remove(adorner);
                    }
                    _adornerLayer.Add(new FingerAdorner(this.Element, FingerNewPos));
                }

                //Go dragging
                if (CanBeDragged)//Check ivm het draggen vanaf een canvas ook of er nog vingers zijn!
                {
                    TransformOnFingers();
                    //goAndDrag();
                    IsDragging = true;
                }
                _oldCenter = _currentCenter;
                _currentCenter = calculateCenterPoint();
                _fingerOldPos = fingerList;

                detectGroups();
                if (t.Selected.Element is UIElement)
                {
                    FrameworkElement parent = MTProcessing.GetInstance().MainWindow;
                    RelativePosition = ((UIElement)t.Selected.Element).TranslatePoint(_lastPosition, parent);
                }
                if (UpdateTouch != null) UpdateTouch(this, new Events.TouchEventArgs(t));
            }
            
        }

        /// <summary>
        /// Get the highest ID (thus the last finger) from the currentfingerlist
        /// </summary>
        /// <returns>ID</returns>
        public double getHighestId()
        {
            double max = -1;
            foreach (FingerObject item in fingerList.Values)
            {
                if (item.Id > max)
                    max = item.Id;
            }
            return max;
        }

        /// <summary>
        /// Go do some resizing. This resize is not working to fine at the moment.
        /// </summary>
        /// <param name="fingerObject"></param>
        private void Resize(FingerObject fingerObject)
        {
            double scaleX;
            double scaleY;
            double scale;
            _tempHeight = Element.ActualHeight;
            _tempWidth = Element.ActualWidth;
            _currentDistance = calculateDistance("current");
            scaleX = ((1 / _oldCurrentDistance.X) * _currentDistance.X);
            scaleY = ((1 / _oldCurrentDistance.Y) * _currentDistance.Y);
            scale = (scaleX + scaleY) / 2;

            if (scale > 0.9 && scale < 1.1)
            {
                Element.Width *= scale;
                Element.Height *= scale;
            }
            _oldCurrentDistance = _currentDistance;
            _fingerOldPos = fingerList;
        }

      
        private bool checkDistance(FingerObject obj)
        {
            if (Math.Abs(obj.CurrentPosition.X - _centerPoint.X) < 10)
                return false;
            if (Math.Abs(obj.CurrentPosition.Y - _centerPoint.Y) < 10)
                return false;
            return true;
        }

        /// <summary>
        /// Set the adornerlayers of an element
        /// </summary>
        /// <param name="fingerCount"></param>
        private void addAdornerLayers(int fingerCount)
        {
            if (Element != Parent)
            {
                if (_fingerStartPos.Count == fingerCount)
                {
                    if (!(Element is MTButton))
                    {
                        _adornerLayer.Add(_simpleCircleAdorner);
                        _adornerLayer.Add(_imageAdorner);
                    }
                    else if (Element is MTButton)
                        _adornerLayer.Add(_keyboardButtonAdorner);
                }
            }
        }

        /// <summary>
        /// Remove the adornerlayers of an element
        /// </summary>
        /// <param name="fingerCount"></param>
        private void removeAdornerLayers(int fingerCount)
        {
            if (Element != Parent)
            {
                if (_adornerLayer.GetAdorners(Element).Length > 0)
                {
                    if (_fingerStartPos.Count == fingerCount)
                    {
                        if (!(Element is MTButton))
                        {
                            _adornerLayer.Remove(_simpleCircleAdorner);
                            _adornerLayer.Remove(_imageAdorner);
                        }
                        else if (Element is MTButton)
                            _adornerLayer.Remove(_keyboardButtonAdorner);
                    }
                }
            }
        }

        /// <summary>
        /// Check if a position of a finger is changed
        /// </summary>
        /// <param name="FingerOldPos">Old finger position</param>
        /// <param name="FingerNewPos">New finger position</param>
        /// <returns></returns>
        private bool fingerPosChanged(FingerObject FingerOldPos, FingerObject FingerNewPos)
        {
            if ((FingerNewPos.x > FingerOldPos.x + 1 || FingerNewPos.x < FingerOldPos.x - 1) ||
                FingerNewPos.y > FingerOldPos.y + 1 || FingerNewPos.y < FingerOldPos.y - 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

     

        double firstAngle;
        double firstLength;
        //        Point firstTranslate;
        Point firstCoordinate;

        Point firstC;

        private long FirstFingerID;
        private int OldFingerCount = 0;
        private int maxFingerCount;

        public enum MovementStates { fingers, fading, moving, none }

        public DispatcherTimer transformTimer;

        public MovementStates movementState = MovementStates.fading;
        
        public MovementStates MovementState
        {
            get
            {
                return movementState;
            }
            set
            {
                // check if transformtimer needs to be started
                if (movementState == MovementStates.none && value != MovementStates.none) StartTransformTimer();

                movementState = value;
                if (movementState == MovementStates.fingers)
                {
                    fadingSpeedX = 0;
                    fadingSpeedY = 0;                                        
                }
                
                if (movementState == MovementStates.none) StopTransformTimer();
                
            }
        }

        private void StopTransformTimer()
        {
            if (transformTimer != null && transformTimer.IsEnabled)
            {
                transformTimer.Stop();
            }
        }

        private void StartTransformTimer()
        {
            if (transformTimer == null || (transformTimer != null && !transformTimer.IsEnabled))
            {
                transformTimer = new DispatcherTimer(DispatcherPriority.Normal);
                transformTimer.Interval = new TimeSpan(0, 0, 0, 0, 30);
                transformTimer.Tick += new EventHandler(transformTimer_Tick);
                transformTimer.Start();
            }
        }

        void transformTimer_Tick(object sender, EventArgs e)
        {
            switch (MovementState)
            {
                case MovementStates.fingers:
                    CalculateSpeed();                    
                    break;
                case MovementStates.fading:
                    TransformOnFading();
                    break;
                case MovementStates.moving:
                    TransformOnMoving();
                    break;

            }
            
            
        }

        private void TransformOnMoving()
        {
            //translateTrans.X = TranslateTarget.X;
            //translateTrans.Y = TranslateTarget.Y;
            //scaleTrans.ScaleX = ScaleTarget.ScaleX;
            //scaleTrans.ScaleY = ScaleTarget.ScaleY;
            //rotateTrans.Angle = RotateTarget.Angle;
            //MovementState = MovementStates.none;
            //Element.RenderTransform = transGroup;
            //ResetFadeCalculations();
            //return;
            //translateTrans = (TranslateTransform)transGroup.Children[0];
            //scaleTrans = (ScaleTransform)transGroup.Children[2];
            //rotateTrans = (RotateTransform)transGroup.Children[1];

            double diffx = (TranslateTarget.X - translateTrans.X) / 4;
            double diffy = (TranslateTarget.Y - translateTrans.Y) / 4;

            
            double scaleX = (ScaleTarget.ScaleX - scaleTrans.ScaleX) / 4;
            double scaleY = (ScaleTarget.ScaleY - scaleTrans.ScaleY) / 4;
            //scaleX = ScaleTarget.ScaleX;
            //scaleY = ScaleTarget.ScaleY;

            // todo smart angle change

            bool add = ((Math.Abs(rotateTrans.Angle - RotateTarget.Angle)) > (RotateTarget.Angle + Math.Abs(360 - rotateTrans.Angle)));

            double angle = add ? ((rotateTrans.Angle + RotateTarget.Angle) / 4) : (rotateTrans.Angle - RotateTarget.Angle) / 4;

            
            //if (angle < 0) angle = -angle;
            

            if (Math.Abs(angle) > 0.00001)
            {
                rotateTrans.Angle -= angle;
                Console.WriteLine(angle.ToString());
            }
            else
            {
                rotateTrans.Angle = RotateTarget.Angle;
            }


            if (Math.Abs(scaleX) > 0.0001 || Math.Abs(scaleY) > 0.0001)

            {
                scaleTrans.ScaleX += scaleX;
                scaleTrans.ScaleY += scaleY;
            }


            if (Math.Abs(diffx) < 0.001 && Math.Abs(diffy) < 0.001)
            {
                translateTrans.X = TranslateTarget.X;
                translateTrans.Y = TranslateTarget.Y;
                scaleTrans.ScaleX = ScaleTarget.ScaleX;
                scaleTrans.ScaleY = ScaleTarget.ScaleY;
                MovementState = MovementStates.none;
                ResetFadeCalculations();
                //Console.WriteLine(scaleTrans.ScaleX.ToString());
            }

            if (Math.Abs(diffx) > 0.001 || Math.Abs(diffy) > 0.001)
            {
                translateTrans.X += diffx;
                translateTrans.Y += diffy;
            }

            
            Element.RenderTransform = transGroup.Clone();
            

        }

        public TranslateTransform TranslateTarget;
        public ScaleTransform ScaleTarget;
        public RotateTransform RotateTarget;

        public void TransformTo(TranslateTransform trans, ScaleTransform scale, RotateTransform rotate)
        {
            TransformGroup tg = new TransformGroup();
            tg.Children.Add(rotate);            
            tg.Children.Add(scale);
            tg.Children.Add(trans);
            
            TransformTo(tg);
            


        }

        public void TransformTo(TransformGroup tg)
        {
            foreach (Transform t in tg.Children)
            {
                if (t is TranslateTransform) TranslateTarget = t as TranslateTransform;
                if (t is RotateTransform) RotateTarget = t as RotateTransform;
                if (t is ScaleTransform) ScaleTarget = t as ScaleTransform;
            }          
            MovementState = MovementStates.moving;
        }

        private void TransformOnFading()
        {
                //Point ShouldBe = element.TransformToVisual(MTProcessing.GetInstance().MainWindow).Transform(firstCoordinate);//_element..PointToScreen(firstCoordinate);
                //Point Translation = new Point(Finger1.X - ShouldBe.X, Finger1.Y - ShouldBe.Y);
            double sx = fadingSpeedX * transformTimer.Interval.TotalMilliseconds;
            double sy = fadingSpeedY * transformTimer.Interval.TotalMilliseconds;
            if (Math.Abs(sx) > 0.3 || Math.Abs(sy) > 0.3)
            {

                translateTrans.X += sx;
                translateTrans.Y += sy;

                //Element.RenderTransform = transGroup;
                fadingSpeedX = fadingSpeedX / 1.15;
                fadingSpeedY = fadingSpeedY / 1.15;
            }
            else
            {
                MovementState = MovementStates.none;
                ResetFadeCalculations();
            }
            
        }

        private void TransformOnFingers()
        {
            // No fingers, no glory
            if (Fingers.Count < 1)
            {
                return;
            }

            FrameworkElement parent = (FrameworkElement)Element.Parent;

            // rotation angle and scale factor to be determined for UI element.
            double angleDiff, scale;

            // Store the absolute position of the first finger in this object.
            Point Finger1 = Fingers[0].CurrentPosition;
            Point Finger1a = processing.MainWindow.TranslatePoint(Finger1, Parent);
            Point fing1 = processing.MainWindow.TranslatePoint(Finger1, Parent);
            
            if (fingerList.Count == 1) 
            {
                if (IsDragging == false)
                {
                    FirstFingerID = Fingers[0].Id;
                    
                    // If we start dragging: store where in our element our first finger is.
                    firstCoordinate = Element.TransformToVisual(processing.MainWindow).Inverse.Transform(fing1);

                    firstCoordinate = Element.TransformToVisual(processing.MainWindow).Inverse.Transform(Finger1);

                    IsDragging = true;
                    OldFingerCount = this.FingerList.Count;
                }
            }
            else
            {

                if (this.FingerList.Count == OldFingerCount)
                {

                    // get current transforms
                    //rotateTrans = (RotateTransform)transGroup.Children[0];
                    //scaleTrans = (ScaleTransform)transGroup.Children[1];
                    //translateTrans = (TranslateTransform)transGroup.Children[2];

                    // Multiple fingers are in our element, we do both translating and transforming
                    // TODO: Could be implemented for 3 or even more fingers.
                    Point Finger2 = Fingers[1].CurrentPosition;
                    Point DistanceVector = new Point((Finger2.X - Finger1.X), (Finger1.Y - Finger2.Y));

                    // determine current angle & length
                    double currentAngle = Math.Atan2(DistanceVector.Y, DistanceVector.X) * 180 / Math.PI;
                    double currentLength = Math.Sqrt(DistanceVector.X * DistanceVector.X + DistanceVector.Y * DistanceVector.Y);
                    
                    // Check whether we start transforming or if we are already in a transformation sequence
                    if (!IsRotating)
                    {
                        // Add the current transformation angle of the object to the angle between fingers.
                        // This way we store any previous rotations.
                        firstAngle = currentAngle + rotateTrans.Angle;

                        // Divide the distance between fingers by the current transformation scale of the object.
                        // This way we store any previous scalings.
                        firstLength = currentLength / scaleTrans.ScaleX;

                        // Calculate position of first finger in element coordinate space.
                        // Used to calculate required translations later on.
                        firstCoordinate = Element.TransformToVisual(processing.MainWindow).Inverse.Transform(Finger1);
                        
                       // TODO: IsScaling shouldn't be neccesary anymore.
                        IsRotating = IsScaling = true;
                    }

                    if (firstLength > 0)
                    {                        

                        // check if element can be rotated
                        if (CanBeRotated)
                        {
                            angleDiff = (firstAngle - currentAngle + 360) % 360;                        
                            rotateTrans.Angle = angleDiff;
                            //transGroup.Children[0] = rotateTrans;                              
                        }

                        // check if element can be scaled
                        if (CanBeScaled)
                        {
                            scale = currentLength / firstLength;
                            scaleTrans.ScaleX = scale;
                            scaleTrans.ScaleY = scale;
                            //transGroup.Children[1] = scaleTrans;
                        }
                    }
                    else
                    {
                        processing.Log("Error - " + currentAngle.ToString("###") + " - " + DateTime.Now.Ticks.ToString());
                    }

                }

            }


            if (fingerList.Count == OldFingerCount)
            {
                Point f = processing.MainWindow.TranslatePoint(Finger1, Parent);

                Point ShouldBe = Element.TranslatePoint(firstCoordinate, Parent);//_element..PointToScreen(firstCoordinate);
                Point Translation = new Point(f.X - ShouldBe.X, f.Y - ShouldBe.Y);

                translateTrans.X += Translation.X;
                translateTrans.Y += Translation.Y;

                //transGroup.Children[2] = translateTrans;
                
                Element.RenderTransform = transGroup;
            }

                     
            
            

            OldFingerCount = this.FingerList.Count;
            return;
        }

        /// <summary>
        /// Objects can not leafe the parent object(canvas)
        /// </summary>
        /// <param name="newHorizontalOffset"></param>
        /// <param name="newVerticalOffset"></param>
        /// <returns></returns>
        private bool clipToBounds(double newHorizontalOffset, double newVerticalOffset)
        {
            if (Element.ClipToBounds)//When cliptobounds is true go into the if statement, when not, return always true
            {
                if (newHorizontalOffset + Width(Element) <= Parent.ActualWidth && newVerticalOffset + Height(Element) <= Parent.ActualHeight &&
                    newHorizontalOffset > 0 && newVerticalOffset > 0)
                    return true;
                else
                    return false;
            }
            else
                return true;
        }

        #region ResolveOffset

        /// <summary>
        /// Determines one component of a UIElement's location 
        /// within a Canvas (either the horizontal or vertical offset).
        /// </summary>
        /// <param name="side1">
        /// The value of an offset relative to a default side of the 
        /// Canvas (i.e. top or left).
        /// </param>
        /// <param name="side2">
        /// The value of the offset relative to the other side of the 
        /// Canvas (i.e. bottom or right).
        /// </param>
        /// <param name="useSide1">
        /// Will be set to true if the returned value should be used 
        /// for the offset from the side represented by the 'side1' 
        /// parameter.  Otherwise, it will be set to false.
        /// </param>
        private static double ResolveOffset(double side1, double side2, out bool useSide1)
        {
            // If the Canvas.Left and Canvas.Right attached properties 
            // are specified for an element, the 'Left' value is honored.
            // The 'Top' value is honored if both Canvas.Top and 
            // Canvas.Bottom are set on the same element.  If one 
            // of those attached properties is not set on an element, 
            // the default value is Double.NaN.
            useSide1 = true;
            double result;
            if (Double.IsNaN(side1))
            {
                if (Double.IsNaN(side2))
                {
                    // Both sides have no value, so set the
                    // first side to a value of zero.
                    result = 0;
                }
                else
                {
                    result = side2;
                    useSide1 = false;
                }
            }
            else
            {
                result = side1;
            }
            return result;
        }

        #endregion // ResolveOffset

        /// <summary>
        /// Get the width of a element
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        private double Width(UIElement element)
        {
            return ((FrameworkElement)element).ActualWidth;
        }
        /// <summary>
        /// Get the height of a element
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        private double Height(UIElement element)
        {
            return ((FrameworkElement)element).ActualHeight;
        }

      

      

      
    }
}
